package com.ruoyi.locksApi.controller;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.lock.domain.*;
import com.ruoyi.lock.mapper.ADeviceMapper;
import com.ruoyi.lock.mapper.AHomeUserMapper;
import com.ruoyi.lock.mapper.ALogsMapper;
import com.ruoyi.lock.mapper.ATenantkeyMapper;
import com.ruoyi.lock.mapper.AOpenlockMapper;
import com.ruoyi.lock.service.IABuildHomeService;
import com.ruoyi.lock.service.IAHomeUserService;
import com.ruoyi.lock.service.IATenantuserService;
import com.ruoyi.lock.service.IAWaringInfoService;
import com.ruoyi.locksApi.domain.*;
import com.ruoyi.locksApi.mapper.ATaskMapper;
import com.ruoyi.locksApi.service.IATaskService;
import com.ruoyi.locksApi.service.IRemoteOpenService;
import com.ruoyi.locksApi.service.LockApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import com.ruoyi.common.core.redis.RedisCache;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.ruoyi.locksApi.service.impl.ApartmentTokenTask;
import com.ruoyi.lock.config.LockApiConfig;
import java.time.LocalDate;
import java.time.ZoneId;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.Base64;
import com.ruoyi.lock.mapper.ABuildHomeMapper;
import com.ruoyi.websocket.WebSocketEndpoint;

@Anonymous
@RestController
@RequestMapping("/cat1lock")
@Slf4j
public class LockApiController extends BaseController {
    @Autowired
    private LockApiService lockApiService;
    @Autowired
    private IATaskService taskService;
    @Autowired
    private ATaskMapper aTaskMapper;
    @Autowired
    private ALogsMapper aLogsMapper;
    @Autowired
    private ADeviceMapper aDeviceMapper;
    @Autowired
    private IAWaringInfoService iaWaringInfoService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ApartmentTokenTask apartmentTokenTask;
    @Autowired
    private ATaskMapper taskMapper;
    @Autowired
    private LockApiConfig lockApiConfig;

    @Autowired
    private IABuildHomeService aBuildHomeService;
    @Autowired
    private IATenantuserService aTenantuserService;
    @Autowired
    private AHomeUserMapper aHomeUserMapper;
    @Autowired
    private ATenantkeyMapper aTenantkeyMapper;
    @Autowired
    private AOpenlockMapper aOpenlockMapper;
    
    @Autowired
    private IRemoteOpenService remoteOpenService;

    @Autowired
    private ABuildHomeMapper aBuildHomeMapper;
    
    // WebSocketEndpoint 是静态方法调用，不需要注入

    // 创建线程池用于异步处理
    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    /**
     * alarm
     */
    @PostMapping("/alarm")
    public JSONObject alarm(@RequestBody alarm alarm) {
        log.info("收到撬锁记录: {}", JSON.toJSONString(alarm));
        AWaringInfo aWaringInfo = new AWaringInfo();

        if(alarm.getType()==2){
            ADevice aDevice = aDeviceMapper.selectADeviceByMac(alarm.getDid());
            aWaringInfo.setMac(alarm.getDid());
            aWaringInfo.setState("0");
            aWaringInfo.setHomeId(String.valueOf(aDevice.getHomeId()));
            aWaringInfo.setWaringType("2");

            int logId = iaWaringInfoService.insertAWaringInfo(aWaringInfo);
        }


        JSONObject jsonObject = new JSONObject();
            jsonObject.put("errorCode", 0);
            jsonObject.put("message", "成功");
            JSONObject data = new JSONObject();
            jsonObject.put("data", null);

        log.info("收到撬锁记录: {}", jsonObject.toJSONString());
        return jsonObject;
    }


    /**
     * alarm
     */
//    @PostMapping("/pushkey")
//    public JSONObject alarm(@RequestBody alarm alarm) {
//        log.info("收到撬锁记录: {}", JSON.toJSONString(alarm));
//        AWaringInfo aWaringInfo = new AWaringInfo();
//
//        if(alarm.getType()==2){
//            ADevice aDevice = aDeviceMapper.selectADeviceByMac(alarm.getDid());
//            aWaringInfo.setMac(alarm.getDid());
//            aWaringInfo.setState("0");
//            aWaringInfo.setHomeId(String.valueOf(aDevice.getHomeId()));
//            aWaringInfo.setWaringType("2");
//
//            int logId = iaWaringInfoService.insertAWaringInfo(aWaringInfo);
//        }
//
//
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("errorCode", 0);
//        jsonObject.put("message", "成功");
//        JSONObject data = new JSONObject();
//        jsonObject.put("data", null);
//
//        log.info("收到撬锁记录: {}", jsonObject.toJSONString());
//        return jsonObject;
//    }

    @PostMapping("/apartmentAddOffLineKey")
    public JSONObject apartmentAddOffLineKey(@RequestBody Map<String, Object> params) {
        String tokenId = redisCache.getCacheObject("apartment:token");
        if (tokenId == null) {
            // 自动登录获取token
            apartmentTokenTask.refreshToken();
            tokenId = redisCache.getCacheObject("apartment:token");
            if (tokenId == null) {
                JSONObject error = new JSONObject();
                error.put("resultCode", 500005);
                error.put("reason", "tokenId不存在或已过期，自动登录失败");
                return error;
            }
        }
        // 写死为今天0点到明天0点
        LocalDate today = LocalDate.now();
        long beginTime = today.atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
        long endTime = today.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
        Map<String, Object> data = new HashMap<>();
        data.put("roomId", params.get("roomId"));
        data.put("beginTime", beginTime);
        data.put("endTime", endTime);
        data.put("keyName", params.getOrDefault("keyName", "离线密码"));
        data.put("authorMode", params.getOrDefault("authorMode", 1));
        Map<String, Object> req = new HashMap<>();
        req.put("method", "apartmentAddOffLineKey");
        req.put("tokenId", tokenId);
        req.put("data", data);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf("text/json;charset=utf-8"));
        headers.add("Content-Version", "1.1");
        HttpEntity<String> entity = new HttpEntity<>(JSONObject.toJSONString(req), headers);
        String respStr = restTemplate.postForObject(lockApiConfig.getLoginUrl(), entity, String.class);
        JSONObject resp = JSONObject.parseObject(respStr);
        // 如果token失效，自动登录并重试一次
        if (resp != null && (resp.getIntValue("resultCode") == 500005 || resp.getIntValue("resultCode") == 304)) {
            apartmentTokenTask.refreshToken();
            tokenId = redisCache.getCacheObject("apartment:token");
            req.put("tokenId", tokenId);
            entity = new HttpEntity<>(JSONObject.toJSONString(req), headers);
            respStr = restTemplate.postForObject(lockApiConfig.getLoginUrl(), entity, String.class);
            resp = JSONObject.parseObject(respStr);
        }
        // 自动解密明文密码
        try {
            if (resp != null && resp.getIntValue("resultCode") == 0 && resp.containsKey("data")) {
                String password = resp.getJSONObject("data").getString("password");
                if (password != null && !password.isEmpty()) {
                    String plainPwd = decryptKey(tokenId, password);
                    resp.getJSONObject("data").put("plainPassword", plainPwd);
                }
            }
        } catch (Exception e) {
            // 解密失败不影响主流程
            resp.getJSONObject("data").put("plainPassword", "解密失败:"+e.getMessage());
        }
        return resp;
    }

    /**
     * 设置回调地址
     * @param  {"callbackurl": "https://xxxx.com/callBackUrl"} 为空则取消回调
     * @return 响应JSON
     */
    @GetMapping("/apartmentCallBackUrlSet")
    public JSONObject apartmentCallBackUrlSet() {
        String tokenId = redisCache.getCacheObject("apartment:token");
        if (tokenId == null) {
            // 自动登录获取token
            apartmentTokenTask.refreshToken();
            tokenId = redisCache.getCacheObject("apartment:token");
            if (tokenId == null) {
                JSONObject error = new JSONObject();
                error.put("resultCode", 500005);
                error.put("reason", "tokenId不存在或已过期，自动登录失败");
                return error;
            }
        }
        Map<String, Object> data = new HashMap<>();
        // 使用配置中的回调URL
        String callbackUrl = lockApiConfig.getCallbackUrl();
        data.put("callbackurl", callbackUrl == null ? "" : callbackUrl);
        Map<String, Object> req = new HashMap<>();
        req.put("method", "apartmentCallBackUrlSet");
        req.put("tokenId", tokenId);
        req.put("data", data);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf("text/json;charset=utf-8"));
        headers.add("Content-Version", "1.1");
        HttpEntity<String> entity = new HttpEntity<>(JSONObject.toJSONString(req), headers);
        String respStr = restTemplate.postForObject(lockApiConfig.getLoginUrl(), entity, String.class);
        JSONObject resp = JSONObject.parseObject(respStr);
        // 如果token失效，自动登录并重试一次
        if (resp != null && (resp.getIntValue("resultCode") == 500005 || resp.getIntValue("resultCode") == 304)) {
            apartmentTokenTask.refreshToken();
            tokenId = redisCache.getCacheObject("apartment:token");
            req.put("tokenId", tokenId);
            entity = new HttpEntity<>(JSONObject.toJSONString(req), headers);
            respStr = restTemplate.postForObject(lockApiConfig.getLoginUrl(), entity, String.class);
            resp = JSONObject.parseObject(respStr);
        }
        return resp;
    }

    /**
     * 单个退房接口
     * @param aHomeUser 退房请求参数
     * @return 响应JSON
     */
    @PostMapping("/apartmentRoomSingleCheckOut")
    public JSONObject apartmentRoomSingleCheckOut(@RequestBody AHomeUser aHomeUser) {

        if (aHomeUser.getHomeId() == null || aHomeUser.getUserId() == null) {
            JSONObject error = new JSONObject();
            error.put("resultCode", 500001);
            error.put("reason", "参数异常：房间ID和用户ID不能为空");
            return error;
        }


        ABuildHome aBuildHome = aBuildHomeService.selectABuildHomeById(aHomeUser.getHomeId());
        ATenantuser aTenantuser = aTenantuserService.selectATenantuserById2(aHomeUser.getUserId());

        AHomeUser aHomeUser1 = aHomeUserMapper.selectHomeUserByUserIdAndHomeId(aTenantuser.getId(), aBuildHome.getId());
        if(aHomeUser1==null){
            JSONObject error = new JSONObject();
            error.put("resultCode", 500007);
            error.put("reason", "该用户已经退房了");
            return error;
        }
        // 将房间ID转换为字符串，用户ID作为邮箱参数传递
        String roomId = aBuildHome.getRoomNum();
        String email = aTenantuser.getIdCardNumber()+"@hflz.com";
        JSONObject result = lockApiService.apartmentRoomSingleCheckOut(roomId, email);

        // 判断返回状态码并处理
        if (result != null) {
            int resultCode = result.getIntValue("resultCode");
            switch (resultCode) {
                case 0:
                    // 成功
                    log.info("退房成功，房间ID: {}, 用户ID: {}", roomId, email);
                    aHomeUserMapper.deleteAHomeUserByIds(new Long[]{aHomeUser1.getId()});
                    aTenantkeyMapper.deleteATenantkeyByHomeIdAndTenantIdRel(aBuildHome.getId(),aTenantuser.getId());
                    // 删除该用户在这个房间的开门记录
                    aOpenlockMapper.deleteAOpenlockByHomeIdAndUserId(aBuildHome.getId(), aTenantuser.getId());
                    break;
                case 500001:
                    log.error("参数异常: {}", result.getString("reason"));
                    break;
                case 500002:
                    JSONObject successResult3 = new JSONObject();
                    successResult3.put("resultCode", 0);
                    successResult3.put("reason", "退房成功");
                    return successResult3;
                case 500003:
                    log.error("房间不存在该房客，房间ID: {}, 用户ID: {}，执行数据清理", roomId, email);
                    aHomeUserMapper.deleteAHomeUserByIds(new Long[]{aHomeUser1.getId()});
                    aTenantkeyMapper.deleteATenantkeyByHomeIdAndTenantIdRel(aBuildHome.getId(),aTenantuser.getId());
                    // 删除该用户在这个房间的开门记录
                    aOpenlockMapper.deleteAOpenlockByHomeIdAndUserId(aBuildHome.getId(), aTenantuser.getId());
                    // 返回成功状态给前端，虽然门锁侧报错，但数据已清理
                    JSONObject successResult = new JSONObject();
                    successResult.put("resultCode", 0);
                    successResult.put("reason", "退房成功");
                    return successResult;
                case 500004:
                    log.error("房间未关联门锁，房间ID: {}", roomId);
                    JSONObject successResult2 = new JSONObject();
                    successResult2.put("resultCode", 0);
                    successResult2.put("reason", "退房成功");
                    return successResult2;
                case 500005:
                    log.error("Token异常: {}", result.getString("reason"));
                    break;
                case 500006:
                    log.error("请求异常: {}", result.getString("reason"));
                    break;
                case 500007:
                    log.info("用户已退房: {}", result.getString("reason"));

                    // 返回成功状态给前端，虽然门锁侧报错，但数据已清理
                    JSONObject successResult4 = new JSONObject();
                    successResult4.put("resultCode", 0);
                    successResult4.put("reason", "退房成功");
                    return successResult4;
                default:
                    log.warn("未知状态码: {}, 原因: {}", resultCode, result.getString("reason"));
                    break;
            }
        }
        
        return result;
    }

    /**
     * 根据用户ID退房接口
     * @param params 退房请求参数 {"userId": "用户ID"}
     * @return 响应JSON
     */
    @PostMapping("/apartmentRoomCheckOut")
    public JSONObject apartmentRoomCheckOut(@RequestBody Map<String, Object> params) {
        // 参数验证
        Long userId = null;
        try {
            userId = Long.valueOf(params.get("userId").toString());
        } catch (Exception e) {
            JSONObject error = new JSONObject();
            error.put("resultCode", 500001);
            error.put("reason", "用户ID不能为空或格式错误");
            return error;
        }

        // 根据用户ID查询用户信息
        ATenantuser aTenantuser = aTenantuserService.selectATenantuserById2(userId);
        if (aTenantuser == null) {
            JSONObject error = new JSONObject();
            error.put("resultCode", 500002);
            error.put("reason", "用户不存在");
            return error;
        }

        // 查询用户关联的房间
        List<AHomeUser> homeUsers = aHomeUserMapper.selectActiveHomeUserByUserId(userId);
        if (homeUsers == null || homeUsers.isEmpty()) {
            JSONObject error = new JSONObject();
            error.put("resultCode", 500003);
            error.put("reason", "该用户未入住任何房间");
            return error;
        }

        // 获取token
        String tokenId = redisCache.getCacheObject("apartment:token");
        if (tokenId == null) {
            // 自动登录获取token
            apartmentTokenTask.refreshToken();
            tokenId = redisCache.getCacheObject("apartment:token");
            if (tokenId == null) {
                JSONObject error = new JSONObject();
                error.put("resultCode", 500005);
                error.put("reason", "tokenId不存在或已过期，自动登录失败");
                return error;
            }
        }

        // 立即返回成功响应，表示接口调用成功
        JSONObject finalResult = new JSONObject();
        finalResult.put("resultCode", 0);
        finalResult.put("reason", "退房请求已接收，正在处理中");
        finalResult.put("method", "apartmentRoomCheckOut");
        finalResult.put("data", new HashMap<>());

        // 异步处理退房逻辑，并通过WebSocket推送结果
        final Long finalUserId = userId;
        final ATenantuser finalATenantuser = aTenantuser;
        final List<AHomeUser> finalHomeUsers = homeUsers;
        final String finalTokenId = tokenId;
        
        CompletableFuture.runAsync(() -> {
            processCheckoutWithWebSocket(finalUserId, finalATenantuser, finalHomeUsers, finalTokenId);
        }, executorService);

        return finalResult;
    }

    /**
     * 异步处理退房并通过WebSocket推送结果
     */
    private void processCheckoutWithWebSocket(Long userId, ATenantuser aTenantuser, List<AHomeUser> homeUsers, String tokenId) {
        try {
            int totalRooms = homeUsers.size();
            int currentCount = 0;
            
            // 处理每个房间
            for (AHomeUser homeUser : homeUsers) {
                // 获取房间信息
                ABuildHome aBuildHome = aBuildHomeService.selectABuildHomeById(homeUser.getHomeId());
                String roomName = aBuildHome != null ? aBuildHome.getRoomName() : "未知房间";
                
                // 处理单个房间退房
                Map<String, Object> result = processRoomCheckOut(homeUser, aTenantuser, tokenId);
                currentCount++;
                
                // 根据结果分类并立即推送
                Boolean success = (Boolean) result.get("success");
                if (success != null && success) {
                    // 退房成功，立即推送成功消息
                    Map<String, Object> successInfo = new HashMap<>();
                    successInfo.put("roomName", roomName);
                    successInfo.put("roomId", homeUser.getHomeId());
                    successInfo.put("message", "退房成功");
                    successInfo.put("userName", aTenantuser.getName());
                    successInfo.put("userId", aTenantuser.getId());
                    
                    // 推送单个房间成功消息
                    String socketId = userId + "_checkout";
                    pushCheckoutMessage(socketId, "checkout_progress", "房间退房成功", totalRooms, currentCount, successInfo);
                    
                } else {
                    // 退房失败，立即推送失败消息
                    String errorMsg = (String) result.get("error");
                    Map<String, Object> errorInfo = new HashMap<>();
                    errorInfo.put("roomName", roomName);
                    errorInfo.put("roomId", homeUser.getHomeId());
                    errorInfo.put("message", "退房失败: " + errorMsg);
                    errorInfo.put("userName", aTenantuser.getName());
                    errorInfo.put("userId", aTenantuser.getId());
                    errorInfo.put("errorCode", result.get("errorCode"));
                    errorInfo.put("errorReason", result.get("errorReason"));
                    
                    // 获取完整的房间地址信息
                    if (aBuildHome != null) {
                        // 使用实体类中的名称字段
                        errorInfo.put("cellName", aBuildHome.getCellName() != null ? aBuildHome.getCellName() : "未知校区");
                        errorInfo.put("unitName", aBuildHome.getUnitName() != null ? aBuildHome.getUnitName() : "未知楼栋");
                        errorInfo.put("floorName", aBuildHome.getFloorName() != null ? aBuildHome.getFloorName() : "未知楼层");
                        errorInfo.put("roomName", aBuildHome.getRoomName() != null ? aBuildHome.getRoomName() : "未知房间");
                    }
                    
                    // 推送单个房间失败消息
                    String socketId = userId + "_checkout";
                    pushCheckoutMessage(socketId, "checkout_progress", "房间退房失败", totalRooms, currentCount, errorInfo);
                }
                
                // 模拟处理时间
                Thread.sleep(10);
            }
            
            // 所有房间处理完成后，推送完成消息
            String socketId = userId + "_checkout";
            Map<String, Object> finalData = new HashMap<>();
            finalData.put("totalRooms", totalRooms);
            finalData.put("message", "所有房间退房处理完成");
            
            pushCheckoutMessage(socketId, "checkout_complete", "退房处理完成", totalRooms, totalRooms, finalData);
            
        } catch (Exception e) {
            log.error("退房处理过程中发生异常", e);
            String socketId = userId + "_checkout";
            pushCheckoutMessage(socketId, "checkout_error", "退房处理异常: " + e.getMessage(), 0, 0, null);
        }
    }



    /**
     * 推送退房结果消息到WebSocket
     */
    private void pushCheckoutMessage(String socketId, String type, String message, int total, int current, Map<String, Object> responseData) {
        try {
            // 构建消息内容
            JSONObject wsMessage = new JSONObject();
            wsMessage.put("type", type);
            wsMessage.put("message", message);
            wsMessage.put("total", total);
            wsMessage.put("current", current);
            wsMessage.put("timestamp", System.currentTimeMillis());
            
            if (responseData != null) {
                wsMessage.put("data", responseData);
            }
            
            // 通过WebSocket推送消息给指定socketId的连接
            String messageJson = wsMessage.toJSONString();
            WebSocketEndpoint.sendMessageToSocketId(socketId, messageJson);
            
            log.info("推送退房结果消息: socketId={}, type={}, message={}", socketId, type, message);
            
        } catch (Exception e) {
            log.error("推送WebSocket消息失败", e);
        }
    }

    /**
     * 房间退租接口
     * @param params 参数，包含roomId
     * @return 退租结果
     */
    @PostMapping("/roomCheckOut")
    public JSONObject roomCheckOut(@RequestBody Map<String, Object> params) {
        // 参数验证
        String roomId = null;
        try {
            roomId = params.get("roomId").toString();
            if (roomId == null || roomId.trim().isEmpty()) {
                JSONObject error = new JSONObject();
                error.put("resultCode", 500001);
                error.put("reason", "房间不能为空");
                return error;
            }
        } catch (Exception e) {
            JSONObject error = new JSONObject();
            error.put("resultCode", 500001);
            error.put("reason", "房间ID不能为空或格式错误");
            return error;
        }

        // 根据房间ID查询房间信息
        ABuildHome aBuildHome = aBuildHomeService.selectABuildHomeById(Long.valueOf(roomId));
        if (aBuildHome == null) {
            JSONObject error = new JSONObject();
            error.put("resultCode", 500002);
            error.put("reason", "房间不存在");
            return error;
        }

        // 获取token
        String tokenId = redisCache.getCacheObject("apartment:token");
        if (tokenId == null) {
            // 自动登录获取token
            apartmentTokenTask.refreshToken();
            tokenId = redisCache.getCacheObject("apartment:token");
            if (tokenId == null) {
                JSONObject error = new JSONObject();
                error.put("resultCode", 500005);
                error.put("reason", "tokenId不存在或已过期，自动登录失败");
                return error;
            }
        }

        // 查询房间下的所有入住用户，用于后续清理本地数据
        List<AHomeUser> homeUsers = aHomeUserMapper.selectActiveHomeUserByHomeId(Long.valueOf(roomId));
        List<ATenantuser> tenantUsers = new ArrayList<>();
        
        if (homeUsers != null && !homeUsers.isEmpty()) {
            for (AHomeUser homeUser : homeUsers) {
                ATenantuser aTenantuser = aTenantuserService.selectATenantuserById2(homeUser.getUserId());
                if (aTenantuser != null) {
                    tenantUsers.add(aTenantuser);
                }
            }
        }

        // 使用异步处理房间退租
        final String currentTokenId = tokenId;
        CompletableFuture<Map<String, Object>> future = CompletableFuture.supplyAsync(() -> {
            return processRoomCheckOutAsync(aBuildHome, currentTokenId);
        }, executorService);

        try {
            Map<String, Object> result = future.get();
            Boolean success = (Boolean) result.get("success");
            Boolean cleaned = (Boolean) result.get("cleaned");
            
            if (success != null && success) {
                // 房间退租成功或清理脏数据成功，异步清理本地数据
                CompletableFuture.runAsync(() -> {
                    try {
                        if (homeUsers != null && !homeUsers.isEmpty()) {
                            for (AHomeUser homeUser : homeUsers) {
                                // 删除入住记录
                                aHomeUserMapper.deleteAHomeUserByIds(new Long[]{homeUser.getId()});
                                // 删除钥匙记录
                                aTenantkeyMapper.deleteATenantkeyByHomeIdAndTenantIdRel(aBuildHome.getId(), homeUser.getUserId());
                            }
                        }
                        // 删除房间的开门记录
                        aOpenlockMapper.deleteAOpenlockByHomeId(aBuildHome.getId());
                        log.info("本地数据清理完成，房间ID: {}, 房间名称: {}", aBuildHome.getRoomNum(), aBuildHome.getRoomName());
                    } catch (Exception e) {
                        log.error("清理本地数据时发生异常", e);
                    }
                }, executorService);
                
                // 构建成功响应
                JSONObject finalResult = new JSONObject();
                Map<String, Object> responseData = new HashMap<>();
                responseData.put("roomId", aBuildHome.getRoomNum());
                responseData.put("roomName", aBuildHome.getRoomName());
                responseData.put("totalUsers", tenantUsers.size());
                
                if (cleaned != null && cleaned) {
                    // 清理脏数据的情况
                    responseData.put("successCount", 0);
                    responseData.put("cleanedCount", tenantUsers.size());
                    responseData.put("failedCount", 0);
                    responseData.put("successUsers", new ArrayList<>());
                    responseData.put("cleanedUsers", tenantUsers.stream().map(user -> {
                        Map<String, Object> userInfo = new HashMap<>();
                        userInfo.put("userName", user.getName());
                        userInfo.put("userId", user.getId());
                        userInfo.put("cleanReason", "房间不存在，已清理脏数据");
                        return userInfo;
                    }).collect(java.util.stream.Collectors.toList()));
                    responseData.put("failedUsers", new ArrayList<>());
                    
                    finalResult.put("resultCode", 0);
                    finalResult.put("reason", "房间退租成功（清理脏数据）");
                } else {
                    // 正常退租成功的情况
                    responseData.put("successCount", tenantUsers.size());
                    responseData.put("cleanedCount", 0);
                    responseData.put("failedCount", 0);
                    responseData.put("successUsers", tenantUsers.stream().map(user -> {
                        Map<String, Object> userInfo = new HashMap<>();
                        userInfo.put("userName", user.getName());
                        userInfo.put("userId", user.getId());
                        return userInfo;
                    }).collect(java.util.stream.Collectors.toList()));
                    responseData.put("cleanedUsers", new ArrayList<>());
                    responseData.put("failedUsers", new ArrayList<>());
                    
                    finalResult.put("resultCode", 0);
                    finalResult.put("reason", "房间退租成功");
                }
                
                finalResult.put("method", "roomCheckOut");
                finalResult.put("data", responseData);
                
                return finalResult;
            } else {
                // 处理错误情况
                String reason = (String) result.get("reason");
                int resultCode = (Integer) result.get("resultCode");
                log.error("房间退租失败，房间ID: {}, 错误码: {}, 原因: {}", aBuildHome.getRoomNum(), resultCode, reason);
                
                JSONObject error = new JSONObject();
                error.put("resultCode", resultCode);
                error.put("reason", reason);
                error.put("method", "roomCheckOut");
                return error;
            }
        } catch (Exception e) {
            log.error("异步处理房间退租时发生异常", e);
            JSONObject error = new JSONObject();
            error.put("resultCode", 500006);
            error.put("reason", "处理异常: " + e.getMessage());
            error.put("method", "roomCheckOut");
            return error;
        }
    }

    /**
     * 异步处理房间退租
     * @param aBuildHome 房间信息
     * @param tokenId token
     * @return 处理结果
     */
    private Map<String, Object> processRoomCheckOutAsync(ABuildHome aBuildHome, String tokenId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 构建请求数据
            Map<String, Object> data = new HashMap<>();
            data.put("roomId", aBuildHome.getRoomNum());
            
            Map<String, Object> req = new HashMap<>();
            req.put("method", "apartmentRoomCheckOut");
            req.put("tokenId", tokenId);
            req.put("data", data);

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.valueOf("text/json;charset=utf-8"));
            headers.add("Content-Version", "1.3");
            
            HttpEntity<String> entity = new HttpEntity<>(JSONObject.toJSONString(req), headers);
            
            // 发送请求
            String respStr = restTemplate.postForObject(lockApiConfig.getLoginUrl(), entity, String.class);
            JSONObject resp = JSONObject.parseObject(respStr);
            
            // 如果token失效，自动登录并重试一次
            if (resp != null && (resp.getIntValue("resultCode") == 500005 || resp.getIntValue("resultCode") == 304)) {
                apartmentTokenTask.refreshToken();
                String newTokenId = redisCache.getCacheObject("apartment:token");
                req.put("tokenId", newTokenId);
                entity = new HttpEntity<>(JSONObject.toJSONString(req), headers);
                respStr = restTemplate.postForObject(lockApiConfig.getLoginUrl(), entity, String.class);
                resp = JSONObject.parseObject(respStr);
            }

            // 处理响应
            if (resp != null) {
                int resultCode = resp.getIntValue("resultCode");
                switch (resultCode) {
                    case 0:
                        // 房间退租成功
                        result.put("success", true);
                        result.put("resultCode", resultCode);
                        result.put("reason", "房间退租成功");
                        log.info("房间退租成功，房间ID: {}, 房间名称: {}", aBuildHome.getRoomNum(), aBuildHome.getRoomName());
                        break;
                    case 500001:
                        // 房间不能为空
                        result.put("success", false);
                        result.put("resultCode", resultCode);
                        result.put("reason", resp.getString("reason") != null ? resp.getString("reason") : "房间不能为空");
                        log.error("房间退租失败 - 房间不能为空，房间ID: {}", aBuildHome.getRoomNum());
                        break;
                    case 500002:
                        // 房间不存在，说明本地数据是脏数据，需要清理
                        result.put("success", true);
                        result.put("resultCode", resultCode);
                        result.put("reason", "房间不存在，已清理脏数据");
                        result.put("cleaned", true);
                        log.info("清理脏数据成功 - 房间不存在，房间ID: {}", aBuildHome.getRoomNum());
                        break;
                    case 500005:
                        // Token异常
                        result.put("success", false);
                        result.put("resultCode", resultCode);
                        result.put("reason", resp.getString("reason") != null ? resp.getString("reason") : "Token异常");
                        log.error("房间退租失败 - Token异常，房间ID: {}", aBuildHome.getRoomNum());
                        break;
                    case 500006:
                        // 请求异常
                        result.put("success", false);
                        result.put("resultCode", resultCode);
                        result.put("reason", resp.getString("reason") != null ? resp.getString("reason") : "请求异常");
                        log.error("房间退租失败 - 请求异常，房间ID: {}", aBuildHome.getRoomNum());
                        break;
                    default:
                        // 未知状态码
                        result.put("success", false);
                        result.put("resultCode", resultCode);
                        result.put("reason", resp.getString("reason") != null ? resp.getString("reason") : "未知错误");
                        log.warn("房间退租失败 - 未知状态码: {}, 房间ID: {}", resultCode, aBuildHome.getRoomNum());
                        break;
                }
            } else {
                result.put("success", false);
                result.put("resultCode", 500006);
                result.put("reason", "请求响应为空");
                log.error("房间退租失败 - 请求响应为空，房间ID: {}", aBuildHome.getRoomNum());
            }
        } catch (Exception e) {
            log.error("房间退租请求异常，房间ID: {}", aBuildHome.getRoomNum(), e);
            result.put("success", false);
            result.put("resultCode", 500006);
            result.put("reason", "请求异常: " + e.getMessage());
        }
        
        return result;
    }

    /**
     * 处理单个房间退房
     * @param homeUser 入住信息
     * @param aTenantuser 用户信息
     * @param tokenId token
     * @return 处理结果
     */
    private Map<String, Object> processRoomCheckOut(AHomeUser homeUser, ATenantuser aTenantuser, String tokenId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 获取房间信息
            ABuildHome aBuildHome = aBuildHomeService.selectABuildHomeById(homeUser.getHomeId());
            if (aBuildHome == null) {
                result.put("success", false);
                result.put("error", "房间信息不存在");
                return result;
            }

            // 构建请求数据
            Map<String, Object> data = new HashMap<>();
            data.put("roomId", aBuildHome.getRoomNum());
            data.put("email", aTenantuser.getIdCardNumber() + "@hflz.com");
            
            Map<String, Object> req = new HashMap<>();
            req.put("method", "apartmentRoomSingleCheckOut");
            req.put("tokenId", tokenId);
            req.put("data", data);

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.valueOf("text/json;charset=utf-8"));
            headers.add("Content-Version", "1.3");
            
            HttpEntity<String> entity = new HttpEntity<>(JSONObject.toJSONString(req), headers);
            
            // 发送请求
            String respStr = restTemplate.postForObject(lockApiConfig.getLoginUrl(), entity, String.class);
            JSONObject resp = JSONObject.parseObject(respStr);
            
            // 如果token失效，自动登录并重试一次
            if (resp != null && (resp.getIntValue("resultCode") == 500005 || resp.getIntValue("resultCode") == 304)) {
                apartmentTokenTask.refreshToken();
                String newTokenId = redisCache.getCacheObject("apartment:token");
                req.put("tokenId", newTokenId);
                entity = new HttpEntity<>(JSONObject.toJSONString(req), headers);
                respStr = restTemplate.postForObject(lockApiConfig.getLoginUrl(), entity, String.class);
                resp = JSONObject.parseObject(respStr);
            }

            // 处理响应
            if (resp != null) {
                int resultCode = resp.getIntValue("resultCode");
                switch (resultCode) {
                    case 0:
                        // 退房成功，删除本地数据
                        aHomeUserMapper.deleteAHomeUserByIds(new Long[]{homeUser.getId()});
                        aTenantkeyMapper.deleteATenantkeyByHomeIdAndTenantIdRel(aBuildHome.getId(), aTenantuser.getId());
                        // 删除该用户在这个房间的开门记录
                        aOpenlockMapper.deleteAOpenlockByHomeIdAndUserId(aBuildHome.getId(), aTenantuser.getId());


                        // 记录成功的房间信息
                        result.put("success", true);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        
                        log.info("用户退房成功，用户ID: {}, 房间ID: {}", aTenantuser.getId(), aBuildHome.getRoomNum());
                        break;
                    case 500001:
                        // 参数异常
                        result.put("success", false);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("errorCode", resultCode);
                        result.put("errorReason", resp.getString("reason"));
                        log.error("参数异常: {}", resp.getString("reason"));
                        break;
                    case 500002:
                        // 房间不存在，说明本地数据是脏数据，需要清理
                        aHomeUserMapper.deleteAHomeUserByIds(new Long[]{homeUser.getId()});
                        aTenantkeyMapper.deleteATenantkeyByHomeIdAndTenantIdRel(aBuildHome.getId(), aTenantuser.getId());
                        // 删除该用户在这个房间的开门记录
                        aOpenlockMapper.deleteAOpenlockByHomeIdAndUserId(aBuildHome.getId(), aTenantuser.getId());
                        
                        // 记录清理的脏数据信息
                        result.put("success", true);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("cleaned", true);
                        result.put("cleanReason", "房间不存在，已清理脏数据");
                        
                        log.info("清理脏数据成功，用户ID: {}, 房间ID: {}, 原因: 房间不存在", aTenantuser.getId(), aBuildHome.getRoomNum());
                        break;
                    case 500003:
                        // 房间不存在该房客，说明本地数据是脏数据，需要清理
                        aHomeUserMapper.deleteAHomeUserByIds(new Long[]{homeUser.getId()});
                        aTenantkeyMapper.deleteATenantkeyByHomeIdAndTenantIdRel(aBuildHome.getId(), aTenantuser.getId());
                        // 删除该用户在这个房间的开门记录
                        aOpenlockMapper.deleteAOpenlockByHomeIdAndUserId(aBuildHome.getId(), aTenantuser.getId());
                        
                        // 记录清理的脏数据信息
                        result.put("success", true);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("cleaned", true);
                        result.put("cleanReason", "房间不存在该房客，已清理脏数据");
                        
                        log.info("清理脏数据成功，用户ID: {}, 房间ID: {}, 原因: 房间不存在该房客", aTenantuser.getId(), aBuildHome.getRoomNum());
                        break;
                    case 700001:
                        // 房间不存在，说明本地数据是脏数据，需要清理
                        aHomeUserMapper.deleteAHomeUserByIds(new Long[]{homeUser.getId()});
                        aTenantkeyMapper.deleteATenantkeyByHomeIdAndTenantIdRel(aBuildHome.getId(), aTenantuser.getId());
                        // 删除该用户在这个房间的开门记录
                        aOpenlockMapper.deleteAOpenlockByHomeIdAndUserId(aBuildHome.getId(), aTenantuser.getId());

                        // 记录清理的脏数据信息
                        result.put("success", true);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("cleaned", true);
                        result.put("cleanReason", "房间不存在，已清理脏数据");

                        log.info("清理脏数据成功，用户ID: {}, 房间ID: {}, 原因: 房间不存", aTenantuser.getId(), aBuildHome.getRoomNum());
                        break;
                    case 500004:
                        // 房间未关联门锁
                        result.put("success", false);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("errorCode", resultCode);
                        result.put("errorReason", resp.getString("reason"));
                        log.error("房间未关联门锁，房间ID: {}", aBuildHome.getRoomNum());
                        break;
                    case 500005:
                        // Token异常
                        result.put("success", false);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("errorCode", resultCode);
                        result.put("errorReason", resp.getString("reason"));
                        log.error("Token异常: {}", resp.getString("reason"));
                        break;
                    case 500006:
                        // 请求异常
                        result.put("success", false);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("errorCode", resultCode);
                        result.put("errorReason", resp.getString("reason"));
                        log.error("请求异常: {}", resp.getString("reason"));
                        break;
                    case 500007:
                        // 用户已退房
                        aHomeUserMapper.deleteAHomeUserByIds(new Long[]{homeUser.getId()});
                        aTenantkeyMapper.deleteATenantkeyByHomeIdAndTenantIdRel(aBuildHome.getId(), aTenantuser.getId());
                        // 删除该用户在这个房间的开门记录
                        aOpenlockMapper.deleteAOpenlockByHomeIdAndUserId(aBuildHome.getId(), aTenantuser.getId());
                        
                        // 记录清理的脏数据信息
                        result.put("success", true);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("cleaned", true);
                        result.put("cleanReason", "用户已退房，已清理脏数据");
                        
                        log.info("清理脏数据成功，用户ID: {}, 房间ID: {}, 原因: 用户已退房", aTenantuser.getId(), aBuildHome.getRoomNum());
                        break;
                    default:
                        // 未知状态码
                        result.put("success", false);
                        result.put("roomId", aBuildHome.getRoomNum());
                        result.put("roomName", aBuildHome.getRoomName());
                        result.put("homeId", aBuildHome.getId());
                        result.put("userName", aTenantuser.getName());
                        result.put("userId", aTenantuser.getId());
                        result.put("errorCode", resultCode);
                        result.put("errorReason", resp.getString("reason"));
                        log.warn("未知状态码: {}, 原因: {}", resultCode, resp.getString("reason"));
                        break;
                }
            } else {
                result.put("success", false);
                result.put("error", "请求响应为空");
            }
        } catch (Exception e) {
            log.error("处理房间退房时发生异常", e);
            result.put("success", false);
            result.put("error", "处理异常: " + e.getMessage());
        }
        
        return result;
    }

    /**
     * 远程开门接口
     * @param params 参数，包含roomNum和可选的keyGroupId
     * @return 开门结果
     */
    @PostMapping("/apartmentOpenDoorLock")
    public JSONObject apartmentOpenDoorLock(@RequestBody Map<String, Object> params) {
        JSONObject response = remoteOpenService.apartmentOpenDoorLock(params);
        
        // 如果返回 resultCode: 500004，更新房间表的 lock_state 字段为 1
        if (response != null && response.getIntValue("resultCode") == 500004) {
            try {
                String roomNum = (String) params.get("roomNum");
                int updateResult = aBuildHomeMapper.updateLockStateByRoomNum(roomNum, 1L);
                if (updateResult > 0) {
                    log.info("房间 {} 的 lock_state 字段已更新为 1", roomNum);
                } else {
                    log.warn("房间 {} 的 lock_state 字段更新失败，可能房间不存在", roomNum);
                }
            } catch (Exception e) {
                log.error("更新房间 lock_state 字段时发生异常", e);
            }
        }
        
        return response;
    }

    // AES解密工具方法
    private static String decryptKey(String tokenId, String pw) throws Exception {
        byte[] md5Byte = MessageDigest.getInstance("MD5").digest(tokenId.getBytes());
        String hexStr = bytesToHex(md5Byte);
        String aesKey = hexStr.substring(8, 24);
        return decrypt(pw, aesKey, aesKey);
    }
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            sb.append(Character.toUpperCase(Character.forDigit((bytes[i] >> 4) & 0x0F, 16)));
            sb.append(Character.toUpperCase(Character.forDigit(bytes[i] & 0x0F, 16)));
        }
        return sb.toString();
    }
    private static String decrypt(String pw, String aesKey, String viPara) throws Exception {
        IvParameterSpec zeroIv = new IvParameterSpec(viPara.getBytes());
        SecretKeySpec key = new SecretKeySpec(aesKey.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
        return new String(cipher.doFinal(Base64.getDecoder().decode(pw)), "UTF-8");
    }
}

